home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 9 / Night Owl CD-ROM (NOPV9) (Night Owl Publisher) (1993).ISO / 001a / seyon213.tz / seyon213 / seyon / SePort.c < prev    next >
C/C++ Source or Header  |  1993-04-04  |  20KB  |  1,053 lines

  1.  
  2. /*
  3.  * This file is part of the Seyon, Copyright (c) 1992-1993 by Muhammad M.
  4.  * Saggaf. All rights reserved.
  5.  *
  6.  * See the file COPYING (1-COPYING) or the manual page seyon(1) for a full
  7.  * statement of rights and permissions for this program.
  8.  */
  9.  
  10. #include "config.h"
  11.  
  12. #include <signal.h>
  13. #include <fcntl.h>
  14. #include <errno.h>
  15. #include <limits.h>
  16.  
  17. #include <X11/Intrinsic.h>
  18.  
  19. #if HAVE_TERMIOS
  20. #include <termios.h>
  21. #else
  22. #if HAVE_TERMIO
  23. #include <termio.h>
  24. #else
  25. #if HAVE_SGTTYB
  26. #include <sys/ioctl.h>
  27. #endif
  28. #endif
  29. #endif
  30.  
  31. #if LF_USE_DEV_NUMBERS
  32. #include <sys/stat.h>
  33. #ifdef SVR4
  34. #include <sys/mkdev.h>
  35. #else
  36. #include <sys/sysmacros.h>
  37. #endif /* SVR4 */
  38. #endif /* LF_USE_DEV_NUMBERS */
  39.  
  40. #if USE_NONSTD_BAUD
  41. #ifdef linux
  42. #include <sys/ioctl.h>
  43. #include <linux/fs.h>
  44. #include <linux/tty.h>
  45. #endif
  46. #endif
  47.  
  48. #include "seyon.h"
  49. #include "SeDecl.h"
  50.  
  51. #if !defined(O_NDELAY) && defined(O_NONBLOCK)
  52. #define O_NDELAY O_NONBLOCK
  53. #endif
  54.  
  55. #if !defined(MAX_INPUT) && defined(_POSIX_MAX_INPUT)
  56. #define MAX_INPUT _POSIX_MAX_INPUT
  57. #endif
  58.  
  59. extern char TtyReadChar();
  60. extern int  TtyReadStr(),
  61.             TtyTimedReadChar(),
  62.             TtyReadLine(),
  63.             TtyTimedWaitFor(),
  64.             IoGetModemStat();
  65.  
  66. extern speed_t  io_get_speed();
  67.  
  68. /*
  69.  * MDELAY is the delay in the output because (on my modem) the command would be
  70.  * ignored if sent at full speed.  Change for other setups. (This setting is
  71.  * for U.S. Robotics Password Modem).
  72.  */
  73.  
  74. #if HAVE_TERMIOS
  75. static struct termios pmode;    /* modem device control structure */
  76. #else
  77. #if HAVE_TERMIO
  78. static struct termio pmode;        /* modem device control structure */
  79. #else
  80. #if HAVE_SGTTYB
  81. static struct sgttyb pmode;
  82. #endif
  83. #endif
  84. #endif
  85.  
  86. char            modem_port[REG_BUF]; /* modem port device file string */
  87. static int      mfd = -1;        /* modem port file descriptor */
  88. int             baudrate = B9600; /* baud rate */
  89.  
  90. void
  91. MdmIFlush()
  92. {
  93.   int TtyIFlush();
  94.   TtyIFlush(mfd);
  95. }
  96.  
  97. void
  98. MdmOFlush()
  99. {
  100.   int TtyOFlush();
  101.   TtyOFlush(mfd);
  102. }
  103.  
  104. void
  105. MdmIOFlush()
  106. {
  107.   int TtyIOFlush();
  108.   TtyIOFlush(mfd);
  109. }
  110.  
  111. void
  112. send_break()
  113. {
  114.   io_send_break(mfd);
  115. }
  116.  
  117. void
  118. MdmPutString(s)
  119.      char           *s;
  120. {
  121.   char            c;
  122.  
  123.   usleep(MDELAY);
  124.   for (; (c = *s); s++) {
  125.     if (*s == '^' && *(s + 1))
  126.       if (*(++s) == '^') c = *s;
  127.       else c = *s & 0x1f;
  128.  
  129.     if (c == '~') sleep(1);
  130.     else send_tbyte(c);
  131.     usleep(MDELAY);
  132.   }
  133. }
  134.  
  135. void
  136. mprintf(fmt, a, b, c)
  137.      char           *fmt,
  138.                     *a,
  139.                     *b,
  140.                     *c;
  141. {
  142.   char            buf[REG_BUF];
  143.  
  144.   sprintf(buf, fmt, a, b, c);
  145.   MdmPutString(buf);
  146. }
  147.  
  148. void
  149. get_modem_attr()
  150. {
  151.   io_get_attr(mfd, &pmode);
  152.   baudrate = io_get_speed(&pmode);
  153. }
  154.  
  155. void
  156. set_modem_attr()
  157. {
  158.   io_set_speed(&pmode, baudrate);
  159.   io_set_attr(mfd, &pmode);
  160. }
  161.  
  162. int
  163. get_modem_fio()
  164. {
  165.   return fcntl(mfd, F_GETFL);
  166. }
  167.  
  168. void
  169. set_modem_fio(fio)
  170.      int             fio;
  171. {
  172.   fcntl(mfd, F_SETFL, fio);
  173. }
  174.  
  175. int
  176. GetModemStat(newModem)
  177.      int             newModem;
  178. {
  179.   static Boolean  useModemControl = True;
  180.   int             retStat;
  181.  
  182.   if (newModem) useModemControl = True;
  183.  
  184.   if (useModemControl && (retStat = IoGetModemStat(mfd)) < 0) {
  185.     SeErrorF("Could not get control line status for device %s", 
  186.              modem_port, "", "");
  187.     SeNotice("Disabling status toggles for that device");
  188.     useModemControl = False;
  189.     qres.ignoreModemDCD = True;
  190.     PopupError("errModemControl", NULL);
  191.   }
  192.   
  193.   return (useModemControl ?  retStat : 0);
  194. }
  195.  
  196. int
  197. Online()
  198. {
  199.   return((GetModemStat(0) & MDM_DCD) ? 1 : 0);
  200. }
  201.  
  202. void
  203. cancel_dial(verbose)
  204.      int             verbose;
  205. {
  206.   MdmPutString(qres.dialCancelString);
  207.   MdmPurge();
  208.  
  209.   if (verbose)
  210.     SeyonMessage("Canceled");
  211. }
  212.  
  213. void
  214. SetInitialModemAttr()
  215. {
  216. #if HAVE_TERMIOS || HAVE_TERMIO
  217.   pmode.c_iflag |= (IGNBRK | IGNPAR);
  218.   pmode.c_iflag &= ~(ISTRIP | BRKINT);
  219.   pmode.c_lflag = 0;
  220.  
  221. #ifdef XCLUDE
  222.   pmode.c_lflag |= XCLUDE;
  223. #endif
  224.  
  225.   pmode.c_oflag &= ~OPOST;        /* transparent output */
  226.   pmode.c_cflag = baudrate | CREAD | CLOCAL;
  227.  
  228.   /* this many characters satisfy reads */
  229.   pmode.c_cc[VMIN] = min(qres.modemVMin, MAX_INPUT);
  230.   pmode.c_cc[VTIME] = 1;        /* or in this many tenths of a second */
  231. #else
  232. #if HAVE_SGTTYB
  233.   pmode.sg_flags = RAW;
  234. #endif
  235. #endif
  236.  
  237.   xc_setflow();
  238.   set_rtscts();
  239. }
  240.  
  241. void
  242. set_rtscts()
  243. {
  244. #ifdef CRTSCTS
  245.   if (qres.rtsctsFlowControl) {
  246.     pmode.c_cflag |= CRTSCTS;
  247.  
  248. #ifdef CNORTSCTS
  249.     pmode.c_cflag &= ~CNORTSCTS;
  250. #endif
  251.  
  252.   }
  253.   else {
  254.     pmode.c_cflag &= ~CRTSCTS;
  255.  
  256. #ifdef CNORTSCTS
  257.     pmode.c_cflag |= CNORTSCTS;
  258. #endif
  259.  
  260.   }
  261. #endif
  262.  
  263.   if (mfd != -1)
  264.     io_set_attr(mfd, &pmode);
  265. }
  266.  
  267. void
  268. xc_setflow()
  269. {
  270.   if (qres.xonxoffFlowControl) {
  271.  
  272. #if HAVE_TERMIOS
  273.     pmode.c_iflag |= IXON | IXOFF;
  274. #else
  275. #if HAVE_TERMIO
  276.     pmode.c_iflag |= IXON | IXOFF;
  277.     pmode.c_iflag &= ~IXANY;
  278. #else
  279. #if HAVE_SGTOBTYB
  280.     pmode.sg_flags |= TANDEM;
  281. #endif
  282. #endif
  283. #endif
  284.  
  285.   }
  286.   else
  287. #if HAVE_TERMIOS
  288.     pmode.c_iflag &= ~(IXON | IXOFF);
  289. #else
  290. #if HAVE_TERMIO
  291.     pmode.c_iflag &= ~(IXON | IXOFF);
  292.     pmode.c_iflag &= ~IXANY;
  293. #else
  294. #if HAVE_SGTTYB
  295.     pmode.sg_flags &= ~TANDEM;
  296. #endif
  297. #endif
  298. #endif
  299.  
  300.   if (mfd != -1)
  301.     io_set_attr(mfd, &pmode);
  302. }
  303.  
  304. char           *
  305. mport(s)            /* get/set port string */
  306.      char           *s;
  307. {
  308.   if (s != NULL)
  309.     strcpy(modem_port, s);
  310.   return (modem_port);
  311. }
  312.  
  313. int
  314. MdmSetGetBaud(baudIndex)
  315.      int             baudIndex;
  316. {
  317.   static char    *baud[] = {"0", "300", "1200", "2400", "4800", "9600", 
  318.                               "19200", "38400", "56700", "115200", NULL};
  319.   long            retBaud;
  320.  
  321.   if (baudIndex != -1)
  322.     retBaud = mbaud(baud[baudIndex]);
  323.   else
  324.     retBaud = mbaud(NULL);
  325.  
  326.   for (baudIndex = 0; baud[baudIndex]; baudIndex++)
  327.     if (atol(baud[baudIndex]) == retBaud)
  328.       return baudIndex;
  329.  
  330.   return -1;
  331. }
  332.  
  333. int
  334. MdmSetGetCSize(bits)
  335.      int             bits;
  336. {
  337.   if (bits != -1) {
  338.     switch (bits) {
  339. #if HAVE_TERMIOS || HAVE_TERMIO
  340.     case 5:
  341.       pmode.c_cflag &= ~CSIZE;
  342.       pmode.c_cflag |= CS5;
  343.       MdmSetGetIStrip(1);
  344.       break;
  345.     case 6:
  346.       pmode.c_cflag &= ~CSIZE;
  347.       pmode.c_cflag |= CS6;
  348.       MdmSetGetIStrip(1);
  349.       break;
  350.     case 7:
  351.       pmode.c_cflag &= ~CSIZE;
  352.       pmode.c_cflag |= CS7;
  353.       MdmSetGetIStrip(1);
  354.       break;
  355.     case 8:
  356.       pmode.c_cflag &= ~CSIZE;
  357.       pmode.c_cflag |= CS8;
  358.       MdmSetGetIStrip((int)qres.stripHighBit);
  359.       break;
  360. #else
  361. #if HAVE_SGTTYB
  362.     case 5:
  363.     case 6:
  364.     case 7:
  365.       pmode.sg_flags |= CBREAK;
  366.       pmode.sg_flags &= ~RAW;
  367.       MdmSetGetIStrip(0);
  368.       break;
  369.     case 8:
  370.       pmode.sg_flags |= RAW;
  371.       pmode.sg_flags &= ~CBREAK;
  372.       MdmSetGetIStrip(0);
  373.       break;
  374. #endif
  375. #endif
  376.     default:
  377.       SeErrorF("invalid number of bits: %d", bits, "", "");
  378.       return -1;
  379.     }
  380.     /* io_set_attr is called in  MdmSetGetIStrip */
  381.   }
  382.  
  383.   if (mfd != -1)
  384.     io_get_attr(mfd, &pmode);
  385.  
  386. #if HAVE_TERMIOS || HAVE_TERMIO
  387.   switch (pmode.c_cflag & CSIZE) {
  388.   case CS5:
  389.     return 5;
  390.   case CS6:
  391.     return 6;
  392.   case CS7:
  393.     return 7;
  394.   case CS8:
  395.     return 8;
  396.   default:
  397.     SeError("Consistency error in number of bits");
  398.     return -1;
  399. #else
  400. #if HAVE_SGTTYB
  401.   switch (pmode.sg_flags & CBREAK) {
  402.   case 0:
  403.     return 8;
  404.   default:
  405.     return 7;
  406. #endif
  407. #endif
  408.   }
  409. }
  410.  
  411. int
  412. MdmSetGetParity(parity)
  413.      int             parity;
  414. {
  415.   if (parity != -1) {
  416.     switch (parity) {
  417. #if HAVE_TERMIOS || HAVE_TERMIO
  418.     case 0:
  419.       pmode.c_cflag &= ~PARENB;
  420.       break;
  421.     case 1:
  422.       pmode.c_cflag |= (PARENB | PARODD);
  423.       break;
  424.     case 2:
  425.       pmode.c_cflag |= PARENB;
  426.       pmode.c_cflag &= ~PARODD;
  427.       break;
  428. #else
  429. #if HAVE_SGTTYB
  430.     case 0:
  431.       pmode.sg_flags &= ~ANYP;
  432.       break;
  433.     case 1:
  434.       pmode.sg_flags |= ODDP;
  435.       pmode.sg_flags &= ~EVENP;
  436.       break;
  437.     case 2:
  438.       pmode.sg_flags |= EVENP;
  439.       pmode.sg_flags &= ~ODDP;
  440.       break;
  441. #endif
  442. #endif
  443.     default:
  444.       SeErrorF("Invalid parity: %d", parity, "", "");
  445.       return -1;
  446.     }
  447.     if (mfd != -1)
  448.       io_set_attr(mfd, &pmode);
  449.   }
  450.  
  451.   if (mfd != -1)
  452.     io_get_attr(mfd, &pmode);
  453.  
  454. #if HAVE_TERMIOS || HAVE_TERMIO
  455.   if (!(pmode.c_cflag & PARENB))
  456.     return 0;
  457.   else if (pmode.c_cflag & PARODD)
  458.     return 1;
  459.   else
  460.     return 2;
  461. #else
  462. #if HAVE_SGTTYB
  463.   switch (pmode.sg_flags & ANYP) {
  464.   case ODDP:
  465.     return 1;
  466.   case EVENP:
  467.     return 2;
  468.   default:
  469.     return 0;
  470.   }
  471. #endif
  472. #endif
  473. }
  474.  
  475. int
  476. MdmSetGetIStrip(flag)
  477.      int             flag;
  478. {
  479. #if HAVE_TERMIOS || HAVE_TERMIO
  480.   if (flag != -1) {
  481.     if (flag)
  482.       pmode.c_iflag |= ISTRIP;
  483.     else
  484.       pmode.c_iflag &= ~ISTRIP;
  485.     
  486.     if (mfd != -1)
  487.       io_set_attr(mfd, &pmode);
  488.   }
  489.  
  490.   if (mfd != -1)
  491.     io_get_attr(mfd, &pmode);
  492.  
  493.   if (pmode.c_iflag & ISTRIP)
  494.     return 1;
  495.   else
  496.     return 0;
  497. #else
  498. #if !HAVE_SGTTYB
  499.   if (mfd != -1)
  500.     io_set_attr(mfd, &pmode);
  501.  
  502.   return 0;
  503. #endif
  504. #endif
  505. }
  506.  
  507. int
  508. MdmSetGetStopBits(bits)
  509.      int             bits;
  510. {
  511. #if HAVE_TERMIOS || HAVE_TERMIO
  512.   if (bits != -1) {
  513.     switch (bits) {
  514.     case 1:
  515.       pmode.c_cflag &= ~CSTOPB;
  516.       break;
  517.     case 2:
  518.       pmode.c_cflag |= CSTOPB;
  519.       break;
  520.     default:
  521.       SeErrorF("invalid number of stop bits: %d", bits, "", "");
  522.       return -1;
  523.     }
  524.     if (mfd != -1)
  525.       io_set_attr(mfd, &pmode);
  526.   }
  527.  
  528.   if (mfd != -1)
  529.     io_get_attr(mfd, &pmode);
  530.  
  531.   if (pmode.c_cflag & CSTOPB)
  532.     return 2;
  533.   else
  534.     return 1;
  535. #else
  536. #if !HAVE_SGTTYB
  537.   if (mfd != -1)
  538.     io_set_attr(mfd, &pmode);
  539.  
  540.   return 1;
  541. #endif
  542. #endif
  543. }
  544.  
  545. /*
  546.  * Get/set the baud rate of the modem port. If the port hasn't been opened
  547.  * yet, just store in pmode for mopen() to use when it opens the port.
  548.  */
  549. long
  550. mbaud(s)
  551.      char           *s;
  552. {
  553. #if USE_NONSTD_BAUD
  554. #ifdef linux
  555.   static struct serial_struct ser_io;
  556.  
  557.   if (ioctl(mfd, TIOCGSERIAL, &ser_io) < 0) {
  558.     SePError("Could not get linux serial info");
  559.     return -1;
  560.   }
  561. #endif
  562. #endif
  563.  
  564.   if (s != NULL) {
  565.     /* this gives a more limited, realistic */
  566.     switch (atol(s)) {           /* range than in sgtty.h */
  567.     case 300:
  568.       baudrate = B300;
  569.       break;
  570.     case 1200:
  571.       baudrate = B1200;
  572.       break;
  573.     case 2400:
  574.       baudrate = B2400;
  575.       break;
  576.     case 4800:
  577.       baudrate = B4800;
  578.       break;
  579.     case 9600:
  580.       baudrate = B9600;
  581.       break;
  582.     case 19200:
  583.       baudrate = B19200;
  584.       break;
  585.     case 38400:
  586.       baudrate = B38400;
  587. #if USE_NONSTD_BAUD
  588. #ifdef linux
  589.       ser_io.flags &= ~ASYNC_SPD_MASK;
  590. #endif
  591. #endif
  592.       break;
  593. #if USE_NONSTD_BAUD
  594. #ifdef linux
  595.     case 56700:
  596.       baudrate = B38400;
  597.       ser_io.flags &= ~ASYNC_SPD_MASK;
  598.       ser_io.flags |= ASYNC_SPD_HI;
  599.       break;
  600.     case 115200:
  601.       baudrate = B38400;
  602.       ser_io.flags &= ~ASYNC_SPD_MASK;
  603.       ser_io.flags |= ASYNC_SPD_VHI;
  604.       break;
  605. #endif
  606. #endif
  607.     default:
  608.       return (-1);
  609.     }
  610.     io_set_speed(&pmode, baudrate);
  611.     if (mfd != -1) {
  612.       io_set_attr(mfd, &pmode);
  613. #if USE_NONSTD_BAUD
  614. #ifdef linux
  615.       if (baudrate == B38400)
  616.     if (ioctl(mfd, TIOCSSERIAL, &ser_io) < 0) {
  617.       SePError("Could not set linux serial info");
  618.       return -1;
  619.     }
  620. #endif
  621. #endif
  622.     }
  623.   }
  624.  
  625.   if (mfd != -1)
  626.     io_get_attr(mfd, &pmode);
  627.  
  628.   switch (io_get_speed(&pmode)) {
  629.   case B300:
  630.     return (300);
  631.   case B1200:
  632.     return (1200);
  633.   case B2400:
  634.     return (2400);
  635.   case B4800:
  636.     return (4800);
  637.   case B9600:
  638.     return (9600);
  639.   case B19200:
  640.     return (19200);
  641.   case B38400:
  642. #if USE_NONSTD_BAUD
  643. #ifdef linux
  644.     if (mfd != -1)
  645.       if (ioctl(mfd, TIOCGSERIAL, &ser_io) < 0) {
  646.         SePError("Could not get linux serial info");
  647.         return -1;
  648.       }
  649.  
  650.     if ((ser_io.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
  651.       return 115200;
  652.     else if ((ser_io.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
  653.       return 56700;
  654.     else
  655. #endif
  656. #endif
  657.       return 38400;
  658.   }
  659.  
  660.   SeError("Consistency error in baud rate");
  661.   return -1;
  662. }
  663.  
  664. /*
  665.  * The following routine is used to hang up the modem.  This is accomplished
  666.  * by setting the baud rate to 0.  According to my documentation on termio,
  667.  * setting the baud rate to zero will result in DTR not being asserted. This
  668.  * hangs up some (most?) modems.  If not, the second part of the routine
  669.  * sends the Hayes modem "escape" and then a hangup command.
  670.  */
  671.  
  672. void
  673. MdmHangup()
  674. {
  675.   int terminalWasActive;
  676.  
  677.   if (mfd == -1) return;
  678.  
  679.   terminalWasActive = SuspContTerminal(TERM_SUSPEND);
  680.   if (qres.hangupViaDTR) {
  681.     io_set_speed(&pmode, B0);    /* set baud 0 (drop DTR) */
  682.     io_set_attr(mfd, &pmode);
  683.  
  684.     sleep(1);                    /* wait a second */
  685.  
  686.     io_set_speed(&pmode, baudrate);    /* reset baud rate */
  687.     io_set_attr(mfd, &pmode);
  688.   }
  689.   else {                        /* use Hayes command */
  690.     sleep(2);                    /* allow for "escape guard time" */
  691.     MdmPutString(qres.modemAttentionString); /* send modem escape command */
  692.  
  693.     sleep(3);                    /* more "escape guard time" */
  694.     MdmPutString(qres.modemHangupString); /* send hangup command */
  695.   }
  696.   MdmPurge();
  697.   if (terminalWasActive) SuspContTerminal(TERM_CONTINUE);
  698.   
  699.   UpdateStatusBox(NULL);
  700. }
  701.  
  702. /*
  703.  * Opens the modem port and configures it. Returns 0 for success or -1 on
  704.  * error.
  705.  */
  706.  
  707. int
  708. OpenModem(modem)
  709.      String modem;
  710. {
  711.   int             LockModem(),
  712.                   UnlockModem();
  713.   void            MdmIOFlush();
  714.   int             oldFlags;
  715.  
  716.   if (modem == NULL || modem[0] == '\0') return ERR_MDM_NOMODEM;
  717.   if (LockModem(modem)) return ERR_MDM_LOCKED;
  718.  
  719.   /* Need O_NDELAY to get the file open before we have carrier */
  720.   if ((mfd = open(modem, O_RDWR | O_NDELAY)) < 0) 
  721.     {UnlockModem(modem); return ERR_MDM_OPENFAILED;}
  722.  
  723.   /* Now, we must reset the O_NDELAY mode so that read() works correctly */
  724.   if (((oldFlags = fcntl(mfd, F_GETFL, 0)) == -1) ||
  725.       (fcntl(mfd, F_SETFL, oldFlags & ~O_NDELAY) == -1)) 
  726.     {UnlockModem(modem); return ERR_MDM_RESETFLAGSFAILED;}
  727.  
  728. #if HAVE_SGTTYB
  729.   if (ioctl(mfd, TIOCEXCL) < 0)
  730.     SePError("exclusive-use");
  731. #endif
  732.  
  733.   mport(modem);
  734.  
  735.   MdmIOFlush();
  736.   SetInitialModemAttr();
  737.   io_set_attr(mfd, &pmode);
  738.  
  739.   GetModemStat(1);
  740.  
  741.   if (mbaud(qres.defaultBPS) == -1)
  742.     se_warningf("invalid default BPS value: %s", qres.defaultBPS, "", "");
  743.   if (MdmSetGetCSize(qres.defaultBits) < 0)
  744.     se_warningf("invalid default number of bits: %s", qres.defaultBits, 
  745.                 "", "");
  746.   if (MdmSetGetParity(qres.defaultParity) < 0)
  747.     se_warningf("invalid default parity value: %s", qres.defaultParity, 
  748.                 "", "");
  749.   if (MdmSetGetStopBits(qres.defaultStopBits) < 0)
  750.     se_warningf("invalid default number of stop bits: %s",
  751.                 qres.defaultStopBits, "", "");
  752.  
  753.   return 0;
  754. }
  755.  
  756. void
  757. ShowOpenModemErrMsg(modemName, retStatus)
  758.      String    modemName;
  759.      int       retStatus;
  760. {
  761.   switch(retStatus) {
  762.   case ERR_MDM_NOMODEM:
  763.     SeError("No Modem Specified");
  764.     break;
  765.   case ERR_MDM_LOCKED:
  766.     SeError(FmtString("Modem ``%s'' is Locked", modemName, "", ""));
  767.     break;
  768.   case ERR_MDM_OPENFAILED:
  769.     SePError(FmtString("Unable to Open Modem ``%s''", modemName, "", ""));
  770.     break;
  771.   case ERR_MDM_RESETFLAGSFAILED:
  772.     SePError(FmtString("Unable to Reset Flags for Modem ``%s''", 
  773.                        modemName, "", ""));
  774.     break;
  775.   default:
  776.     SeError(FmtString("Unknown Error While Openeong Modem ``%s''", 
  777.                       modemName, "", ""));
  778.     break;
  779.   }
  780. }
  781.  
  782. void
  783. close_modem()
  784. {
  785.   if (mfd != -1)
  786.     close(mfd);
  787. }
  788.  
  789. /*
  790.  * Attach standard input and output to the modem port. This only gets called
  791.  * after a fork by the child process; which then exec's a program that uses
  792.  * standard i/o for some data transfer protocol. (To put this here is
  793.  * actually a kludge, but I wanted to keep the modem-specific stuff in a
  794.  * black box.)
  795.  */
  796. void
  797. mattach()
  798. {
  799.   extern int dup2();
  800.   /*
  801.    * attach standard i/o to port
  802.    */
  803.   dup2(mfd, 0);                    /* close local stdin and connect to port */
  804.   dup2(mfd, 1);                    /* close local stdout and connect to port */
  805.  
  806.   close(mfd);                    /* close the old port descriptor */
  807. }
  808.  
  809. /* ------------------------------------------------------------
  810.  * Routines to read from the modem.
  811.  */
  812.  
  813. /*
  814.  * MdmReadStr: reads a bunch of characters from the modem.
  815.  */
  816.  
  817. int
  818. MdmReadStr(buf)
  819.      char           *buf;
  820. {
  821.   return TtyReadStr(mfd, buf);
  822. }
  823.  
  824. /*
  825.  * MdmReadChar: reads one character from the modem.
  826.  */
  827.  
  828. char
  829. MdmReadChar(readChar)
  830.      char           *readChar;
  831. {
  832.   return TtyReadChar(mfd, readChar);
  833. }
  834.  
  835. int
  836. MdmTimedReadChar(readChar, expireTime)
  837.      char           *readChar;
  838.      int             expireTime;
  839. {
  840.   return TtyTimedReadChar(mfd, readChar, expireTime);
  841. }
  842.  
  843. /*
  844.  * MdmReadLine: reads one line from the modem.
  845.  */
  846.  
  847. int
  848. MdmReadLine(buf)
  849.      char           *buf;
  850. {
  851.   return TtyReadLine(mfd, buf);
  852. }
  853.  
  854. int
  855. MdmTimedWaitFor(expectedString, waitTime)
  856.      char           *expectedString;
  857.      int             waitTime;
  858. {
  859.   return TtyTimedWaitFor(mfd, expectedString, waitTime);
  860. }
  861.  
  862. /*
  863.  * MdmPurge: throws away all incoming characters until no more are sent.
  864.  */
  865.  
  866. void
  867. MdmPurge()
  868. {
  869.   char            c;
  870.   while (MdmTimedReadChar(&c, 1) >= 0);
  871. }
  872.  
  873. #ifdef retired
  874. int
  875. readbyte(seconds)
  876.      int             seconds;
  877. {
  878.   return trminp(mfd, seconds);
  879. }
  880. #endif
  881.  
  882. /*
  883.  *    Output a byte to the modem port. All data sent to the modem
  884.  *    is output through this routine.
  885.  */
  886.  
  887. void
  888. sendbyte(ch)
  889.      int             ch;
  890. {
  891.   char            c = ch & 0xff;
  892.  
  893.   if (write(mfd, &c, 1) < 0)
  894.     SePError("character write");
  895. }
  896.  
  897. void
  898. sendf_slowly(format, a, b, c)
  899.      char           *format,
  900.                     *a,
  901.                     *b,
  902.                     *c;
  903. {
  904.   char            buffer[SM_BUF];
  905.  
  906.   sprintf(buffer, format, a, b, c);
  907.   send_slowly(buffer);
  908. }
  909.  
  910. void
  911. send_slowly(s)
  912.      char           *s;
  913. {
  914.   while (*s) {
  915.     sendbyte(*s++);
  916.     /*
  917.      * avoid busy waiting by using usleep if available. adjust MDELAY if
  918.      * you're having trouble
  919.      */
  920.     usleep(MDELAY);
  921.   }
  922. }
  923.  
  924. /*
  925.  * lock_tty() returns non-zero if the lock file exists (prevents Seyon from
  926.  * running).
  927.  *
  928.  * unlock_tty() deletes the lock file.
  929.  *
  930.  * Simple, eh?
  931.  */
  932.  
  933. char            lckf[SM_BUF];
  934. char            ltmp[SM_BUF];
  935. pid_t           lockPid;
  936.  
  937. int
  938. LockModem(modem)
  939.      String modem;
  940. {
  941.   strcpy(modem_port, modem);
  942.   return lock_tty();
  943. }
  944.  
  945. int
  946. UnlockModem(modem)
  947.      String modem;
  948. {
  949.   unlock_tty();
  950.   return 0;
  951. }
  952.  
  953. int
  954. lock_tty()
  955. {
  956.   int             lfd;
  957.   pid_t           pid,
  958.                   lckpid;
  959.   char           *modemname;
  960. #if LF_USE_ASCII_PID
  961.   char            pidstr[20],
  962.                   lckpidstr[20];
  963.   int             nb;
  964. #endif
  965. #if LF_USE_DEV_NUMBERS
  966.   struct stat  mbuf;
  967. #endif
  968.  
  969.   /* Get our PID, and initialize the filename strings */
  970.   pid = getpid();
  971.  
  972. #if !LF_USE_DEV_NUMBERS
  973.   modemname = strrchr(modem_port, '/');
  974.   sprintf(lckf, "%s/%s%s", LF_PATH, LF_PREFIX, 
  975.           (modemname ? (modemname + 1) : modem_port));
  976. #else
  977.   if(stat(modem_port, &mbuf) < 0) {
  978.     SePErrorF("could not stat modem port %s", modem_port, "", "");
  979.     return -1;
  980.   }
  981.   sprintf(lckf,"%s/%s%03u.%03u.%03u", LF_PATH, LF_PREFIX, major(mbuf.st_dev),
  982.           major(mbuf.st_rdev), minor(mbuf.st_rdev));
  983. #endif /* LF_USE_DEV_NUMBERS */
  984.  
  985.   sprintf(ltmp, "%s/%s%d", LF_PATH, "LTMP.", pid);
  986.   /* Create the LTMP.<pid> file and scribble our PID in it */
  987.   unlink(ltmp);
  988.   if ((lfd = creat(ltmp, 0644)) == -1) {
  989.     SePErrorF("Could not create temporary lock file %s", ltmp, "", "");
  990.     return -1;
  991.   }
  992.  
  993. #if LF_USE_ASCII_PID
  994.   sprintf(pidstr, "%10d\n", pid);
  995.   write(lfd, pidstr, 11);
  996. #else
  997.   write(lfd, (char*)&pid, sizeof(pid));
  998. #endif
  999.   close(lfd);
  1000.  
  1001.   /*
  1002.    * Attempt to link directly - if it works, we're done.
  1003.    */
  1004. relink:
  1005.   if (link(ltmp, lckf) == 0) {
  1006.     unlink(ltmp);
  1007.     lockPid = pid;
  1008.     return 0;
  1009.   }
  1010.  
  1011.   /*
  1012.    * Oh brother, there's a LCK..* file already; we must now expend effort to
  1013.    * learn if it's stale or not.
  1014.    */
  1015.   if ((lfd = open(lckf, O_RDONLY)) != -1) {
  1016.  
  1017. #if LF_USE_ASCII_PID
  1018.     for (nb = 0; nb < 20 && read(lfd, lckpidstr + nb, sizeof(char)); nb++);
  1019.     if (nb) {
  1020.       lckpid = atol(lckpidstr);
  1021. #else
  1022.     if (read(lfd, (char *)&lckpid, sizeof(lckpid)) == sizeof(lckpid)) {
  1023. #endif
  1024.  
  1025.       lockPid = (pid_t) lckpid;
  1026.       if (kill(lckpid, 0) == 0) {
  1027.         SeErrorF("Device %s is locked by process %d", modem_port, lckpid, "");
  1028.         unlink(ltmp);
  1029.         return -1;
  1030.       }
  1031.     }
  1032.   }
  1033.  
  1034.   /*
  1035.    * The LCK..* file was stale.  Remove and retry.
  1036.    */
  1037.   if (unlink(lckf)) {
  1038.     SePErrorF("Unable to unlink stale lock file \"%s\"", lckf, "", "");
  1039.     unlink(ltmp);
  1040.     return -1;
  1041.   }
  1042.   goto relink;
  1043.   /* NOTREACHED */
  1044. }
  1045.  
  1046. void
  1047. unlock_tty()
  1048. {
  1049.   /* Don't remove the lock file unless it's the one we created */
  1050.   if (getpid() == lockPid)
  1051.     unlink(lckf);
  1052. }
  1053.